package com.insight.entity;

import com.insight.common.enums.ExportFormat;
import com.insight.common.enums.ExportStatus;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

/**
 * T079: 数据字典导出实体
 * 记录数据字典导出任务的历史和文件信息
 *
 * @author Insight Team
 */
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "dictionary_export", indexes = {
        @Index(name = "idx_export_datasource", columnList = "datasource_id")
})
@EntityListeners(AuditingEntityListener.class)
public class DictionaryExport {

    /**
     * 主键ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /**
     * 关联的数据源
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "datasource_id", nullable = false)
    @NotNull(message = "数据源不能为空")
    private DataSource dataSource;

    /**
     * 导出格式
     * MARKDOWN, HTML, EXCEL, PDF
     */
    @NotNull(message = "导出格式不能为空")
    @Enumerated(EnumType.STRING)
    @Column(name = "export_format", length = 20, nullable = false)
    private ExportFormat format;

    /**
     * 导出文件名
     * 包含扩展名，如: testdb_dictionary_20250101.md
     */
    @NotNull(message = "文件名不能为空")
    @Column(name = "file_name", length = 500, nullable = false)
    private String fileName;

    /**
     * 本地文件路径
     * 存储在服务器本地文件系统的路径
     * 可为null（文件已归档到MinIO后删除）
     */
    @Column(name = "local_path", length = 1000)
    private String localPath;

    /**
     * MinIO对象存储路径
     * 存储在MinIO的对象路径，如: exports/2025/01/testdb_dictionary.md
     * 可为null（未归档或仅本地存储）
     */
    @Column(name = "minio_path", length = 1000)
    private String minioPath;

    /**
     * 文件大小（字节）
     * 用于显示和存储空间统计
     * 可为null（导出失败时无文件）
     */
    @Column(name = "file_size")
    private Long fileSize;

    /**
     * 文件过期时间
     * 超过此时间文件将被清理
     * 可为null（永不过期）
     */
    @Column(name = "expires_at")
    private LocalDateTime expiresAt;

    /**
     * 是否已归档到MinIO
     * true: 已归档，本地文件可能已删除
     * false: 未归档，仅本地存储
     */
    @Column(name = "is_archived", nullable = false)
    private Boolean isArchived = false;

    /**
     * 导出状态
     * SUCCESS: 导出成功
     * FAILED: 导出失败
     * EXPIRED: 文件已过期
     */
    @NotNull(message = "导出状态不能为空")
    @Enumerated(EnumType.STRING)
    @Column(name = "status", length = 20, nullable = false)
    private ExportStatus status;

    /**
     * 创建时间（导出任务开始时间）
     */
    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;

    /**
     * 判断文件是否已过期
     *
     * @return true 如果expiresAt不为null且已过期
     */
    public boolean isExpired() {
        if (expiresAt == null) {
            return false;
        }
        return LocalDateTime.now().isAfter(expiresAt);
    }

    /**
     * 判断文件是否可下载
     *
     * @return true 如果状态为SUCCESS且未过期
     */
    public boolean isDownloadable() {
        return status == ExportStatus.SUCCESS && !isExpired();
    }

    /**
     * 获取文件存储位置描述
     *
     * @return 存储位置说明
     */
    public String getStorageLocation() {
        if (isArchived && minioPath != null) {
            return "MinIO: " + minioPath;
        } else if (localPath != null) {
            return "本地: " + localPath;
        } else {
            return "无文件";
        }
    }

    /**
     * 获取格式化的文件大小
     *
     * @return 人类可读的文件大小，如 "2.5 MB"
     */
    public String getFormattedFileSize() {
        if (fileSize == null || fileSize == 0) {
            return "0 B";
        }
        if (fileSize < 1024) {
            return fileSize + " B";
        }
        if (fileSize < 1024 * 1024) {
            return String.format("%.2f KB", fileSize / 1024.0);
        }
        if (fileSize < 1024L * 1024 * 1024) {
            return String.format("%.2f MB", fileSize / (1024.0 * 1024));
        }
        return String.format("%.2f GB", fileSize / (1024.0 * 1024 * 1024));
    }
}
